#include <stdio.h>

#include "casl.h"

#include "os.h"

#include "execute.h"
#include "instructions.h"

/* assemble.c */
int GetSentenceLineNo (UWORD address);
/* memory.c */
void CodeRead (UWORD address, CODE * code);

UWORD end_PC;			/* get value in assemble.c:assemble() */

int statusRunning = FALSE;	/* have Running or not */

static void
init (void)			/* init the registers */
{
  /* init registers */
  memcpy (&reg, &initreg, sizeof (reg));

  statusRunning = TRUE;
}

/* return operantion no */
static int
execute (void)			/* execute one instruction */
{
  CODE code;

  CodeRead (reg.PC, &code);	/* operation including operand */
  if (code.op > 0 && code.op < MO_NUM)
    {
      (mot[code.op].execute) (code.GRno, code.ADR, code.XRno);
      reg.PC += 2;		/* point to next instruction */
      if (reg.PC > end_PC)
	reg.PC = end_PC;
    }
  else
    {
      display (_("No instruction in address: %d\n"), reg.PC);
      reg.PC = end_PC;
    }

  return code.op;
}

/* trace
 *
 * return
 *   the line number which will run next
 *   -1 means the program exited
 */
int
trace (void)
{
  int i, j;

  if (!statusRunning)		/* reg.PC>=end_PC||reg.PC==initreg.PC */
    {
      init ();
      statusRunning = TRUE;
    }
  else if (reg.PC < end_PC)
    {
      i = GetSentenceLineNo (reg.PC);

      for (j = 0; j < sentences[i].length; j += 2)
	execute ();
    }

  if (reg.PC < end_PC)
    i = GetSentenceLineNo (reg.PC);
  else
    {
      display (_("The program exited.\n"));
      statusRunning = FALSE;
      i = -1;
    }

  return i;
}

/* step
 *
 * return
 *   the line number which will run next
 *   -1 means the program exited
 */
int
step (void)
{
  int i, j;

  if (!statusRunning)		/* reg.PC>=end_PC||reg.PC==initreg.PC */
    {
      init ();
      statusRunning = TRUE;
    }
  else if (reg.PC < end_PC)
    {
      i = GetSentenceLineNo (reg.PC);

      if (strcmp (mot[sentences[i].op].name, "CALL") == 0) /* CALL instruction */
	while (reg.PC < end_PC
	       && reg.PC != sentences[i].address + sentences[i].length)
	  execute ();
      else
	for (j = 0; j < sentences[i].length; j += 2)
	  execute ();
    }

  if (reg.PC < end_PC)
    i = GetSentenceLineNo (reg.PC);
  else
    {
      display (_("The program exited.\n"));
      statusRunning = FALSE;
      i = -1;
    }
  return i;
}

void
cont (void)
{
  if (!statusRunning)
    init ();

  while (reg.PC < end_PC)
    execute ();
}

void
run (void)
{
  init ();

  while (reg.PC < end_PC)
    execute ();

  statusRunning = FALSE;
}
